package com.cby.code.util;

import java.io.PipedOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * Description:ReflectionUtils
 * @see  <a>https://blog.csdn.net/qq_44715943/article/details/120587716</a>
 * @author chenbaoyang
 * @create 2022/7/1 14:32
 */
public class ReflectionUtils {

    /**
     * 通过完整的类名字符串来判断类是否存在
     * @param clzName 完整的类名（packageName+Class）
     * @return
     */
    public static boolean isClassExist(String clzName) {
        Class<?> clz = getClass(clzName);
        return clz != null;
    }

    /**
     * 通过完整的类名字符串来判断类是否存在
     * @param clzName 完整的类名（packageName+Class）
     * @return
     */
    public static Class<?> getClass(String clzName) {
        Class<?> clz = null;
        try{
            clz = Class.forName(clzName);
        } catch (ClassNotFoundException e) {
            CbyLogUtils.e("Class not found");
        }
        return clz;
    }

    /**
     * 获取对象
     * @param clzName 完整的类名（packageName+Class）
     * @return
     */
    public static <T> T getInstance(String clzName) {
        Class<?> clz = getClass(clzName);
        return getInstance(clz);
    }

    /**
     * 获取对象
     * @param clz 完整的类名（packageName+Class）
     * @return
     */
    public static <T> T getInstance(Class clz) {
        if(clz != null) {
            try {
                Object o = clz.newInstance();
                return (T) o;
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 获取对象
     * @param clzName   完整的类名（packageName+Class）
     * @param argTypes  参数类型
     * @param args      实际参数
     * @return <T>
     */
    public static <T> T getInstance(String clzName, Class[] argTypes, Object... args) {
        Class<?> clz = getClass(clzName);
        return getInstance(clz, argTypes, args);
    }

    /**
     * 获取对象
     * @param clz       类
     * @param argTypes  参数类型
     * @param args      实际参数
     * @return <T>
     */
    public static <T> T getInstance(Class clz, Class[] argTypes, Object... args) {
        if(clz != null) {
            Constructor c1 = null;
            try {
                // 获取无参数构造方法
                // Constructor c2 = vipClass.getDeclaredConstructor();
                c1 = clz.getDeclaredConstructor(argTypes);
                Object obj = c1.newInstance(args);
                return (T) obj;
            } catch (NoSuchMethodException e) {
                CbyLogUtils.e("Method not found in "+clz.getName()+"class");
            } catch (IllegalAccessException e) {
                CbyLogUtils.e("Illegal Access");
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    /**
     * 指定类名和方法名，已经方法参数执行该方法
     * <p>
     * getMethod（）：获取自身能用所有的公共方法。1.类本身的public 2.继承父类的public 3.实现接口的public
     * getDeclaredMethod（）：获取类自身声明的所有方法。
     * </p>
     * @param clzName
     * @param methodName
     * @param argTypes
     * @param args
     * @return T
     */
    public static <T> T invokeMethod(String clzName, String methodName, Class[] argTypes, Object... args) {
        Class<?> clz = getClass(clzName);
        return invokeMethod(clz, methodName, argTypes, args);
    }

    /**
     * 指定类和方法名，已经方法参数执行该方法
     * <p>
     * getMethod（）：获取自身能用所有的公共方法。1.类本身的public 2.继承父类的public 3.实现接口的public
     * getDeclaredMethod（）：获取类自身声明的所有方法。
     * </p>
     * @param clz
     * @param methodName
     * @param argTypes
     * @param args
     * @return T
     */
    public static <T> T invokeMethod(Class clz, String methodName, Class[] argTypes, Object... args) {
        Object o = getInstance(clz);
        if(o == null) {
            return null;
        }
        Method method;
        Object resultObj;
        try {
            method = clz.getDeclaredMethod(methodName, argTypes);
            resultObj = method.invoke(o,args);
        } catch (NoSuchMethodException e) {
            CbyLogUtils.e("Method not found in "+clz.getName()+"class");
            return null;
        } catch (IllegalAccessException e) {
            CbyLogUtils.e(e.getMessage());
            return null;
        } catch (InvocationTargetException e) {
            CbyLogUtils.e(e.getMessage());
            return null;
        }
        return (T) resultObj;
    }

    /**
     * 给指定的类的成员属性赋值
     * @param clzName    类名称
     * @param fieldName  目标属性
     * @param value      具体值
     */
    public static void setFieldValue(String clzName, String fieldName, Object value) {
        Class clz = getClass(clzName);
        setFieldValue(clz, fieldName, value);
    }

    /**
     * 给指定的类的成员属性赋值
     * @param clz    类
     * @param fieldName  目标属性
     * @param value      具体值
     */
    public static void setFieldValue(Class clz, String fieldName, Object value) {
        Object obj = getInstance(clz);
        if(obj != null) {
            Field targetField = null;
            try {
                targetField = clz.getDeclaredField(fieldName);
                targetField.setAccessible(true);
                targetField.set(obj, value);
            } catch (NoSuchFieldException e) {
                CbyLogUtils.e("No such Field");
            } catch (IllegalAccessException e) {
                CbyLogUtils.e("Illegal Access");
            }
        }
    }

    /**
     * 给指定的类的成员属性赋值
     * @param clzName    类名称
     * @param fieldName  目标属性
     */
    public static <T> T getFieldValue(String clzName, String fieldName) {
        Class clz = getClass(clzName);
        return getFieldValue(clz, fieldName);
    }

    /**
     * 给指定的类的成员属性赋值
     * @param clz    类
     * @param fieldName  目标属性
     */
    public static <T> T getFieldValue(Class clz, String fieldName) {
        Object obj = getInstance(clz);
        if(clz != null && obj != null) {
            Field targetField;
            try {
                targetField = clz.getDeclaredField(fieldName);
                targetField.setAccessible(true);
                return (T) targetField.get(obj);
            } catch (NoSuchFieldException e) {
                CbyLogUtils.e("No such Field");
            } catch (IllegalAccessException e) {
                CbyLogUtils.e("Illegal Access");
            }
        }
        return null;
    }

    /**
     * 获取指定的属性的class
     * @param clzName    类名称
     * @param fieldName  目标属性
     * @return
     */
    public static Type getFieldType(String clzName, String fieldName){
        Class clz = getClass(clzName);
        return getFieldType(clz, fieldName);
    }

    /**
     * 获取指定的属性的class
     * @param clz    类
     * @param fieldName  目标属性
     * @return
     */
    public static Type getFieldType(Class clz, String fieldName){
        Object obj = getInstance(clz);
        if(clz != null && obj != null) {
            Field targetField = null;
            try {
                targetField = clz.getDeclaredField(fieldName);
                targetField.setAccessible(true);
                return targetField.getType();
            } catch (NoSuchFieldException e) {
                CbyLogUtils.e("No such Field");
            }
        }
        return null;
    }


    /**
     * 获取父类
     * @param clzName    类名称
     * @return
     */
    public static Class getSuperClass(String clzName) {
        Class clz = getClass(clzName);
        return getSuperClass(clz);
    }

    /**
     * 获取父类
     * @param clz    类
     * @return
     */
    public static Class<?> getSuperClass(Class clz) {
        if(clz != null) {
            return clz.getSuperclass();
        }
        return null;
    }

    /**
     * 获取当前类实现的所有接口
     * @param clzName    类名称
     * @return
     */
    public static Class<?>[] getInterfaces(String clzName) {
        Class clz = getClass(clzName);
        return getInterfaces(clz);
    }

    /**
     * 获取当前类实现的所有接口
     * @param clz    类
     * @return
     */
    public static Class<?>[] getInterfaces(Class clz) {
        // 获取String的父类
        return clz.getInterfaces();
    }

    /**
     * 获取当前类声明的泛型类
     * @param clz
     * @return
     */
    public static Class<?> getParameterizedType(Class clz, int position) {
        if(clz == null) {
            return null;
        }
        Class modelClass;
        Type type = clz.getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Type[] types = ((ParameterizedType)type).getActualTypeArguments();
            if(position <types.length && position >= 0){
                return  (Class)((ParameterizedType)type).getActualTypeArguments()[position];
            }
        }
        return null;
    }
}
